home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AmigActive 10
/
AACD 10.iso
/
AACD
/
Online
/
SpeakFreely
/
src
/
log.doc
< prev
next >
Wrap
Text File
|
2000-05-18
|
114KB
|
2,413 lines
Speak Freely for Unix
(formerly netfone)
Development Log
by John Walker
http://www.fourmilab.ch/
26 August 1995
John Gilmore encountered an undefined symbol irint when building on
SunOS 4.1.3_U1. Apparently this function, which is part of the main C
library in 4.1.1, was moved somewhere else in 4.1.3. To put an end of
this irint() nonsense once and for all, I rewrote the expression in
soundbyte.c to eliminate the call to irint() entirely.
John also suggested making the distribution tar extract into a
netfone-<version> directory as most GNU packages do. Starting with
release 5.1, which will extract into a netfone-5.1 directory, that's
how it'll be.
29 August 1995
Added logic to mike to calculate the precise number of samples which
will fit in a sound buffer to optimally fill a single UDP packet.
John Gilmore pointed out that sending lots of individual packets on
our own is actually more efficient than forcing the network driver to
break large packets into fragments. It also reduces the sound delay,
since we don't have to wait for a large sound buffer to be filled
before getting it on it's way to the other end.
Note that even though mike will now never send a packet larger than
512 bytes, speaker continues to be able to handle packets with as
many as 8000 samples and thus remains compatible with older versions of
mike.
31 August 1995
Added -d and -q switches to speaker which, if specified, override the
debug mode specified in incoming packets. The -d switch is
particularly handy when you want to log every packet and don't have
control over the sending end. The -q switch allows running speaker in
the background without worrying about where the output is going to go
is somebody starts sending with debug mode on.
To reduce network traffic and improve conference call performance,
I made push-to-talk (-b) mode the default in mike. Continuous
transmission (unless squelched) is selected with the -a switch.
1 September 1995
Added ADPCM compression to mike (enabled by the -f switch) and decompression
to speaker. ADPCM halves the number of bytes in a packet without substantial
degradation of voice-grade audio, far less than that of the -c switch,
which achieves the same degree of compression. You can specify -c
and -f together for a 4x reduction in bandwidth, with substantial loss
of quality. ADPCM and GSM compression cannot be used simultaneously.
ADPCM compression is provided primarily as an alternative to Simple
(-c) compression for users with a 64 Kb connection who don't have a
fast enough CPU to run GSM. ADPCM is much faster on both compression and
decompression than GSM.
2 September 1995
Release 5.1.
15 September 1995
Implemented a crude but better-than-nothing "answering machine" in
speaker. Specifying the "-rfile" option records all sound received
in the named file in Sun .au format (including header). If you
specify "-r+file" the sound is appended to the named file if it
exists. As with a real answering machine with the volume turned up,
the sound is still played. Obviously there are a zillion nice things
that one can immediately think of which would improve this feature,
but at least it provides a stopgap which captures attempts to
communicate while you were away from the machine.
17 September 1995
Discovered that a "quick fix" in the SGI audio input soundgrab()
function in soundbyte.c was violating the maximum packet size for
memory-constrained versions of WINSOCK. Fixing that was
straightforward, but I ran squarely into a bug where we'd hang trying
to flush queued input when transitioning to talk mode in push-to-talk.
I added a new soundflush() function dedicated to flushing the input
queue (however that is accomplished) and provided Sun and SGI
implementations of this function.
Lots of little changes all over to transition the package name from
Netfone to Speak Freely for Unix. Much more remains to be done,
particularly separating the option sections for sfmike and sfspeaker
in the man page.
19 September 1995
Finished changes to programs, Makefile, and manual page for renaming
to Speak Freely for Unix.
Version 5.2 released.
20 September 1995
Added time and date to the "connect" and "idle" messages produced by
the -v option on sfspeaker.
21 September 1995
Installed the ability to automatically generate, encrypt with PGP, and
transmit a session key to the receiving machine. Since PGP is invoked
to encrypt and decrypt the key, Speak Freely remains free of any RSA
patent issues; the user simply obtains and installs the correct
version of PGP and Speak Freely automatically provides public key
support compatible with PGP. To encrypt sound to one or more people
with a public key, use the:
-z"user1 user2..."
option on sfmike. The user names are the same as you specify on the
PGP command line when encrypting files.
On the receiving end, when a PGP-encrypted session key is received,
PGP is invoked to decrypt it. Decryption requires your RSA private
key, for which the pass phrase must be provided. By default, PGP
asks you for the pass phrase each time a session is initiated. You
can override this by specifying the pass phrase using the PGPPASS
environment variable (see the PGP documentation for details and a
discussion of the vulnerability this may create) or by using the
-z"Pass phrase"
option on speaker. The given pass phrase is then passed to PGP with
its own -z option each time it is invoked.
23 September 1995
Sfmike didn't accept numeric IP addresses--only resolvable host names.
Fixed to call inet_addr then only try gethostbyname() if it fails.
Mike.c and speaker.c printed IP addresses the hard way. I changed
them to use inet_ntoa.
Speaker.c failed to reload the loop variable used when searching for
an active connection at the start of each search. This could lead
to segmentation faults after connections had been closed. Fixed.
Connections kept around to preserve their PGP session keys caused the
10 second timer not to be canceled after all connections have gone
idle. Fixed.
Support for half-duplex audio devices. If HALF_DUPLEX is defined
at compile time, sfmike sends the copy of sfspeaker running on the
local host a pair of fHalfDuplex messages with the fHalfDuplexMute and
fHalfDuplexResume bits set. On receiving a fHalfDuplexMute, sfspeaker
closes the audio device, if open, and sets a flag which causes all
audio input to be discarded. When fHalfDuplexResume is received,
audio input is enabled, to be acquired upon receipt of the next sound
buffer.
Integrated fixes from Andrey A. Chernov to allow compiling for
FreeBSD, using its Sun-like /dev/audio device.
24 September 1995
First cut at IP Multicast support. Multicast support is included only
if IP_ADD_MEMBERSHIP is defined at compile time; we assume that it
will be defined only on system with mrouted. If multicast is present,
sfspeaker recognises the "-Mhost/ip" option to indicate one or more
Multicast groups to which it should add membership. Sound packets
from any of the named multicast groups as well as those sent directly
to the bound port will be played.
On the sfmike side, multicast thresholds can be specified by an
integer after the multicast group name or IP number, delimited by a
slash. To transmit to a continent-wide multicast group you might use
the command:
sfmike 230.1.217.11/128
Users who fret over the security risks inherent in the PGPPASS or
-z"Pass phrase" method of supplying the pass phrase to PGP but can't
stand having to enter the pass phrase for every new session key now
have a new option. If you specify "-z" with no pass phrase on the
call to speaker, it prompts you for the pass phrase once at the start
of execution, then supplies that phrase to PGP for all subsequent
connections. Note however that the pass phrase is passed to PGP with
its -z option, so whatever risk that creates remains present.
Renamed "one-time pad" to "key file" and included a note about its
cryptographic shortcomings in the manual page.
25 September 1995
More fixes from Andrey A. Chernov for FreeBSD--the include of
sys/timeb.hin netfone.h was conditioned on "sun" not "BSD_like",
soundflush() in soundbyte.c needed to use a read() loop and test
EAGAIN rather than the Sun-specific FIONREAD ioctl(), and debug output
from mike.c looks better if cbreak() mode is used rather than raw().
5 October 1995
Added debug mode output to sfspeaker to indicate when it's off
calling PGP to decode a session key and whether the process
succeeded or failed. The long pauses were disturbing when you
didn't know what was going on.
6 October 1995
Added the mellifluous new ring.au to the standard release.
Feature release 5.3.
15 October 1995
Added the "-Pport" option to speaker.c to specify which port it
listens on. If specified, this overrides the INTERNET_PORT defined in
the Makefile.
Allowed specification of the port mike.c transmits to as a number
appended to the hostname or IP address, delimited by a colon. The
port, if specified, must appear before any multicast scope
specification. Thus, a multicast address with port and scope
specified would appear like:
227.11.133.51:5050/64
5 November 1995
Finished implementation of Look Who's Listening, with changes in
speaker.c to notify the server, and new modules lwld.c (the server)
and lwl.c (the client). The manual pages have been split up into a
separate page for each program.
Disabled all of the RTP support except that needed for Look Who's
Listening. It isn't ready for prime time, and there's no reason to
delay LWL, which everybody is screaming for, to wait for it.
6 November 1995
Added support for the LPC compression mode (-lpc) included in the RTP
spec. It's tricky to set up, since any clipping of audio drives it
absolutely nuts, but 12-to-1 compression is worth the bother if you
have a slow link. You can enable -lpc and -c at the same time, but
the result is so poor it's not worth trying.
7 November 1995
Added an -n option to speaker.c which causes it to ignore any ring
requests from remote hosts. This is for Sun users who've hooked a
good sound system up to the audio output jack and get irritated when a
remote ring switches it back to the built-in speaker.
Feature release 5.5.
19 November 1995
Integrated fixes for various warning messages from GCC 2.7.0 for
Solaris reported by Mark B. Hamby. Two of these were legitimate bugs
in lwl.c and lwld.c, but would actually cause a problem only in the
extremely unlikely circumstance of malloc() failing on the allocation
of a small buffer. The rest were just complaints about failure to
cast pointers to the (char *) defined for some of the socket calls.
I created a new "contrib" directory for third party software that
is not directly integrated into Speak Freely. The first item is
"tkshell", a Tcl/Tk/Tix interface to Speak Freely, also developed
by Mark Hamby.
Sfspeaker showed connect and idle messages even if the "-v" option
was not present. Fixed.
Some of the cases in mike.c where a user tried to specify more than
one of the compression modes -F, -LPC, and -T didn't exit after
printing the error message. This resulted in the program trying to
actually use more than one of these modes at once, which could
heroically mess things up. Fixed.
Added a gimmick to make it easier to reply to a host that's just
connected to your machine, avoiding all the fumble-fingered typing or
furious cutting and pasting. If you specify the
-a"filename[ command ...]"
option to sfspeaker, every time a new host connects, it will write
an executable shell script that invokes sfmike to reply to the
just-connected host. If no command is given, "sfmike -t $* hostname"
is used, the $* allowing the user to pass options from the call on
the reply script to sfmike. A custom command can be specified following
the filename, separated by a space (be sure to quote the string in
this case).
21 November 1995
Discovered bad htonl() logic in loop-back code in sfspeaker. The
length passed to sendto() had already been byte swapped. Fixed.
24 November 1995
Made GSM (-t) compression the default in mike.c. Far, far, too many
people are choosing improper compression modes, so I've made GSM the
default for both the Unix and Windows versions. The mutually
exclusive compression modes (ADPCM, LPC, and GSM) now simply cancel
a previously selected mode radio-button style rather than give an
error message. This preserves compatibility with earlier versions
which allowed "sfmike -f", for example, without requiring an -n
switch to turn off GSM.
Converted speaker.c from alarm() to setitimer(), allowing timer
resolution as fine as permitted by the system clock, with
specification in microseconds. A wrapper called ularm() which accepts
an argument in microseconds hides the ugliness of setitimer(). This
will allow the rapid-fire time-based event generation needed to
download face files from a remote server. This, of course, required
little fixes all over the place.
Discovered that going from idle to audio output active state in
speaker.c didn't speed up the timeout interval to the active rate
until the next timeout occurred. Fixed to speed up the timer at the
moment audio output is opened.
Renamed netfone.h to speakfree.h, eliminating the last vestige of the
program's original identity.
26 November 1995
Fixed a format in lwld.c that caused an incorrect error message
when the -m message file couldn't be opened.
Integrated the "show your face" code to permit users to see each
other's pictures. A user can make a face image available by creating
a 256 colour Microsoft .BMP format file and providing its pathname to
sfspeaker on a SPEAKFREE_FACE environment variable. When sound is
received from a new host, sfspeaker sends a request for a face image
to it. If an image is available, is is transferred in packets at a
rate configured by FaceFetchInterval in speakfree.h (in microseconds),
and when complete, displayed using "xv" (which must be installed and
accessible from the user's PATH). Actually, as long as the two
communicating systems are Unix, any image format displayable by xv can
be used, but since the Windows version only knows how to display .BMP
files, even Unix users should restrict themselves to that format. (I
may add code to enforce this in the future.)
The somewhat radical changes in timeout logic required to support
transmission of the face image in the background ran afoul of the
sneaky way we were keeping timed out connections around to avoid
forgetting their PGP session keys. Now a con_timeout value of -1
indicates a ghost of a former connection, not (hosttimeout + 1), which
can't be guaranteed with variable timer resolution. I changed the
"Tick..." message generated when the -d option is set to show the
current timer interval.
Forking processes to view face images with xv was incrementing
reference counts of resources inherited by the child process. On
Sun, this locked up the exclusive use /dev/audio file until all the
viewer processes terminated. I added code to release all resources
inherited from the parent as soon as the child process receives
control. Audio output, if open, is unconditionally closed before
the fork() since we don't know the nature of the resource(s) it may
bequeath to the child process. It will simply be reacquired when the
next packet arrives.
28 November 1995
Eliminated an unreferenced variable in the HDX_DEBUG code in
speaker.c.
Changed speaker.c -d option output to show the hostname from the
connection (obtained with gethostbyname) rather than the often
truncated and untrustworthy hostname in the sound buffer. If the
hostname could not be obtained, the IP address is shown.
To aid in diagnosing the problems of users who connect with
inappropriate compression modes, I added a status message to the
-v option output which identifies the type of compression currently
being used by a connected host. The message is reissued every time
the compression mode changes.
Changed the logic of the "show your face" code to make it fully
downward compatible with earlier releases. If SPEAKFREE_FACE is
defined and points to a valid file, mike.c now includes a new
fFaceOffer bit in every sound packet it sends. speaker.c only
requests a face from the remote host if that host's packet includes
the fFaceOffer bit. Since prior releases won't ever set that bit,
there's no need to worry about them getting befuddled by receiving
face requests they don't know how to process.
30 November 1995
Integrated a fix from Hans Werner Strube which corrects the problem
sending sound files on Solaris. Due to confusion resulting from the
change-over from the BSD ftime() function which returns time as
seconds and milliseconds to the System V gettimeofday() which returns
seconds and microseconds, the delays computed to wait for the
transmission of sound buffers were 1000 times too long, resulting in a
long pause between each packet. Fixed.
Increased the default host timeout from 1 to 3 minutes. Connections
would frequently time out during long rants by the local user,
requiring retransmission of the face file. This should ameliorate
the problem for the time being, pending a longer-term fix based
on RTP BYE packet handshaking.
1 December 1995
Integrated a Solaris fix from Hans Werner Strube into mike.c and
soundbyte.c which sets the audio input buffer to the actual packet
size currently in use. This reduces the delay compared to the
previous fixed packet size of 4000 samples. The actual buffer size
may be rounded down to the nearest multiple of 16 on machines which
use the DBRI device.
Feature release 5.6.
2 December 1995
Added a fix for FreeBSD from Andrey A. Chernov to add a required
library to the FreeBSD link command. His other fix, to comment out
the compiler-busting warning in RTPOUT.C since GCC requires correct
syntax even in #ifdef disabled code was already in 5.6, thanks to GCC
users on Solaris who encountered the same problem.
4 December 1995
Hans Werner Strube supplied another Solaris / System V fix required
for the viewerterm() function in speaker.c. The wait3() function
present in BSD and SGI IRIX is supplanted by waitpid() in System V. As
integrated, waitpid() is currently used only on Solaris. When I get
time to do more testing, I may change the code to use it
unconditionally, as even SunOS 4.1.1 seems to implement it.
5 December 1995
Our clever decision to not initialise the socket until after
processing the command line options in speaker.c (so that -u works
even if another copy of sfspeaker is running) ran afoul of the need
for the -M option (possibly several -M options) to have the socket
initialised in order to add multicast group memberships. I moved the
socket initialisation back to before the option processing loop.
(Reported by Robert Kaempf).
Added a first-pass option processing loop before the socket is
initialised to restore the ability to use -u when another copy of
sfspeaker is running and, more importantly, allow the -p option to
change the port number before the socket is bound.
8 December 1995
Andrey A. Chernov discovered that lwl.c and lwld.c still contained
numerous assumptions about both byte order and the layout of bit
fields (used in the header of the RTP- compatible packets those
programs exchange). I installed the bit-twiddling version of the
packet processing from the Windows version, leaving in the original
code, disabled with #ifdef RationalWorld, since it documents what
we're trying to accomplish a lot more clearly. The fixed code works
fine on big-endian machines, but I haven't been able to test it on a
little-endian myself, so it's probable I may have missed one or more
additional fixes that may be required.
Given the generally ratty state of sflwl (runs for a week without
a hitch, then crashes 3 times in one day for no apparent reason),
I added a bunch of new debug output when the -v option is selected
including logging of all requests to the server. Maybe this will
provide some clues as to what's going on.
9 December 1995
Integrated fixes to the Makefile and soundbyte.c which enable the
program to build and run on Linux.
19 December 1995
Well, the earlier fixes to lwl.c and lwld.c improved (or at least
changed) the results of trying to run sflwl on FreeBSD, but it still
doesn't work right. Still flying blind, I took another close look at
lwl.c and lwld.c and found two places in each where, under certain
circumstances, a compiler treating "char" as signed might lead to
trouble. I added defensive ANDs with 0xFF in both cases. We'll see
if that does it.
Found one more little-endian problem in lwl.c--this time it was a
reference to a bit field in the RTP packet which caused sflwl to
mis-count the number of items returned from sflwld. Fixed.
While sflwld detected packet overflow and flagged it to the
requestor, it didn't actually stop filling the packet. Fixed.
Including sys/wait.h pulled in signal.h before _BSD_SIGNALS was
defined on the SGI, leading to naughty System V-like behaviour
complete with sflwld crashing with "Alarm clock" since it failed
to re-enable SIGALRM in release(). For good measure (and to
preempt other System V problems), I both defined _BSD_SIGNALS at the
top of the includes and included a re-enable of SIGALRM in release().
Distinguished the new debug output added yesterday from the regular
sysadmin-level logging by enabling the former by the "-vv" option
(very verbose) and the latter by "-v". Detailed output (-vv)
always enables the regular verbose messages.
Integrated the first-cut Hewlett-Packard audio driver code submitted
by Marc Kilian. Marc notes that this code has not been extensively
tested. It's up to you, HP workstation users, to wring this out and
bring HP into the list of fully-supported platforms. You can enable
debug output by uncommenting the #define HP_DEBUG at the top of
hp_audio.c.
20 December 1995
Fixed a few more byte-order and bitfield problems, this time in
rtpout.c.
Added some additional information to the "very verbose" trace from
sflwld when -vv is specified, including the SDES of any SDES or
BYE packet and the 4 letter code of APP messages.
21 December 1995
Oops--missed a FreeBSD fix in the Makefile. It's in there now.
As suggested by John Deters, I added an explicit "+armor=off"
specification to the command lines used to invoke PGP in mike.c and
speaker.c. Our use of PGP to exchange a random session key requires
PGP to produce a binary output file, not an ASCII armoured one, as it
usually does unless the "a" option is specified. The user can,
however, make ASCII armour the default by setting the "Armor=on"
option in the config.txt file; doing so caused Speak Freely's use of
PGP to fail. Configuring armor off on the command line overrides the
config.txt specification and prevents this problem.
27 December 1995
Edward Olszewski reported that the "cc" compiler on HPUX 9.05 (HP 9000
735/125) (like SunOS cc) couldn't handle the "const" modifier in the
argument declarations in md5/md5.c. To avoid an ever-growing
exception list, I just removed the "const". It won't make any
difference in operation.
In addition, random() (referenced in lpc/lpc.c) was undefined in the
link. I modified lpc.c to enable the emulation of random() with
lrand48 for HEWLETT_PACKARD as well as Solaris.
31 December 1995
On some systems (Silicon Graphics, for instance) if the sfspeaker
timer happens to expire while we're waiting for the fread() from
the PGP session key decode pipe to complete (this usually happens
when it takes the user longer to enter the secret key pass phrase
than the interval to the next timer tick), the fread() can return
with zero bytes read and errno set to EINTR (Interrupted system call).
I modified to the logic that reads from the PGP decode pipe in
speaker.c to detect this condition and re-issue the fread() until
it either succeeds or fails with a status other than EINTR.
4 January 1996
Finished first cut of sfecho (echo.c), a remote echo server intended
to allow users, even those with half-duplex audio hardware, to perform
remote "sound checks" of various compression and encryption modes
without the need for an individual on the other end to evaluate sound
quality. The server simply time stamps sound packets as they arrive,
then sends them back to the originating address ten seconds later.
No audio I/O is performed, so the echo server can be run on a machine
without audio capability.
5 January 1996
The microsecond-resolution packet timing in echo.c will overflow a
long and go negative in less than an hour. The way the code was
structured, this actually didn't cause any trouble unless a packet
happened to be queued right at the time the wrap-around caused the
sign to change. I modified the code to use a double for the packet
time to make sure there's no wrap-around.
I changed the logic in makeSessionKey() in echo.c to use only MD5, not
idearand(), to construct the RTP SDES sent to the LWL server. Since
there's no other reason to include IDEA in sfecho, eliminating this
one reference gets rid of the whole IDEA patent disclaimer on the
sfecho.1 manual page.
The logic in echo.c is perfectly capable of supporting a face image
file for the echo server, for which I was originally planning to use
an image of a statue of the Greek goddess Echo. Well, not only
haven't I been able to locate such an image, on reflection (hee, hee)
I've decided that giving the echo server a face is a bad idea,
especially for a widely-used public server running on a line with
limited bandwidth. It would be very easy for the volume of face data
sent to all accessors to dwarf the sound packet bandwidth, inducing
pauses and lost data that gave echo server users a false impression of
the actual response. Not being one to ever actually delete working
code, I turned off the echo face capability with #ifdefs on ECHO_FACE
so it can be restored if future events prove that to be wise.
8 January 1996
The echo server program, echo.c, inherited logic from speaker.c to
disable publication of its identity on the SPEAKFREE_LWL_TELL server
if a connection is refused. This is intended to keep machines which
once ran an LWL server but don't any more from being repeatedly
bombarded with LWL packets. Unfortunately, this means that if an LWL
server is momentarily out of service, the echo server will disappear
from the LWL directory until it restarts the next time; this is bad.
So, I removed the disabling due to connection refused in echo.c,
trusting the administrator of an echo server to be responsible enough
to respond to the repeated warning messages for refused connections
when an LWL server is genuinely rather than transiently down.
In an attempt to fix the sporadic "broken pipe" crashes of the sflwld
server (every three or four days on the SGI, typically), I'm
proceeding on the hypothesis that this happens when a user submits a
request and then shuts down (or crashes) before we write the reply
back to the socket. (I have not, however, even with a deliberately
broken version of sflwl, been able to make this happen.) Anyway, I
added a SIGPIPE signal catcher which ignores the signal (at the
moment, printing a message when this happens). This should allow the
send() to return and the connection to be closed normally. There's
nothing else we can do about it anyway.
10 January 1996
The critical section locking code in echo.c wasn't entirely
bulletproof against a host timeout occurring while processing a sound
packet from that host, or while scanning the connection chain and/or
making an entry for a new host. I revised the logic to include all
references to the connection chain as well as the queued packet list
within the critical section that blocks the timer interrupt. In
addition, I revised the detection of host timeouts and LWL
retransmissions in release() to be based on absolute time rather than
a countdown timeout. This permits release() to be called at any time
whatsoever without worrying about whether the proper timeout interval
has elapsed and, hence, to be called whenever the critical section
lock is released if the timeout has expired while the lock was set.
This timeout logic is a lot cleaner and deserves to be integrated into
speaker.c once it's proven in the more demanding environment (due to
rapid-fire packet timing interrupts) of echo.c.
21 January 1996
Added a hexadecimal dump (-x) option to sfspeaker if it's
compiled with HEXDUMP defined. One more little tool to help
debug RTP and VAT support.
Found a place in speaker.c's LPC decompression function
lpcdecomp() where an ntohl() was needed in extracting the
decompressed length of the message.
28 January 1996
Staked another bloodsucking byte-order dependency in lpccomp() in
mike.c.
Added a reality-check in playbuffer() in speaker.c which discards
packets with a buffer.buffer_len field longer than the actual packet
read from the socket. This prevents embarrassing blasts of noise or
worse if we receive a garbage packet due to improper protocol
recognition or an incorrect encryption key on an RTP or VAT
connection.
Playbuffer() in speaker.c made a redundant test on showhosts. Fixed.
Added monitoring of the control port (data port + 1) to speaker.c to
recognise VAT and RTP connections. A new con_protocol field in the
connection structure indicates the protocol of the connection. The
reply command will now contain the sfmike appropriate option to send
in the protocol we're receiving.
29 January 1996
Integrated a decode-only version of Dave Hawkes' VOX compression mode.
I'm not close to being able to make the compressor available, but at
least this this code in place, Unix users can receive packets sent by
the Windows version with this compression mode. All the encoding
logic is present in the module VOX.C, but disabled pending
integration.
Made innumerable fixes in the VAT and RTP support code and associated
packet translators. For the moment, everything is pretty much working
except for LPC; neither NEVOT nor VAT seem to be able to talk to one
another in LPC mode so I'm not sure the problem is of my making. GSM
and all the other common modes work fine. It's a little odd that VAT
ID and RTP SDES packets are sent by sfmike as well as sfspeaker; to be
marked as a participant in a conference you have to run sfmike with
its ID (though you do not have to actually transmit anything). I may
change this, but for the moment getting this logic into the Windows
version (which does not share our schizophrenic view of connections)
is a much higher priority.
31 January 1996
The "plumber()" code in lwld.c that catches SIGPIPE signals when a
remote user disconnects while we're tring to send the reply to a query
seems to be working well. So, to tempt fate, I disabled the log
message when we recover from a SIGPIPE.
After struggling 2 days trying to figure out why I could receive
LPC-encoded sound just fine from VAT, and send it to myself with no
trouble in LPC format, but was unable to send LPC sound to VAT, I
decided to download a newer VAT. I got the 4.0a2 alpha release, and
no trouble with LPC in either direction. I guess it just didn't work
in earlier versions of VAT.
To avoid confusing those familiar with VAT, mike.c now parses
destinations in any of the following formats:
hostname
hostname:port
hostname/port
hostname:port/ttl
hostname/port/ttl
Integrated DES encryption code into the VAT and RTP output handlers
in mike.c. Like everything else in the funhouse of VAT and RTP,
results are mixed. Clearly VAT and I agree on key generation, since
the sound I send is played OK, but with ticking between each
packet in GSM mode, indicating VAT doesn't handle the padding of
packets to 8 bytes correctly. Well, thank goodness RTP introduced
the "P" flag! But NEVOT doesn't seem to recognise any DES encrypted
inbound packets in RTP mode! So, let's try the new VAT--uhhhh, it
appears they've totally pulled DES support from it due to "export
control" restrictions. Gosh this is fun.
1 February 1996
After several more hours of psychoanalysis of the RTP spec and
examination of the VAT and RTP source code, DES encryption of RTP
packets works in both directions when I test with NeVoT 3.32. I can't
test RTP encryption with VAT 4.0.a2 alpha since they've disabled
encryption due to ITAR fears. At present, I assume that if RTP
encryption is enabled, both control and data packets will be
encrypted, and this is how NeVoT behaves. RTP allows RTCP control
channel packets to be either encrypted or in the clear--you're
supposed to detect a clear packet by verifying that it meets
rather easy-to-spoof consistency conditions. This gives me the
willies; I'll defer such "heuristics" until things settle out more in
RTP land.
With even more hacking, I can now talk to NeVoT in RTP mode both
directions with DES encryption, more or less. The less is that for
some reason ADPCM picks up noise and, of course, LPC doesn't work
right (but it never did, even without DES). VAT doesn't pad packets
when encrypting, and I haven't guess the golden rule that governs how
the packet is initialised when it is encrypted. (Hint: it isn't
zeroed--I tried that.)
Integrated a fix from Paul Eggert for Solaris 2.5 in mike.c. In
Solaris 2.5 gettimeofday() is required to have two arguments--you have
to pass an explicit NULL if you don't want the time zone information.
Both references that failed to supply the NULL now do.
Removed the terminal protocol dependent modules from libdes.a to avoid
nugatory incompatibilities in ports.
2 February 1996
Modified rtp_make_sdes() and rtp_make_bye() in rtpacket.c to
optionally create a composite RTCP packet with a void Receiver Report
at the start if called with a new "strict" argument TRUE. The RTP
spec requires an RTCP packet to always begin with a (possibly void) SR
or RR. Why make it optional? I had missed this little twist when I
implemented lwld.c, and though I'll fix lwld.c to accept packets in
this format, existing servers won't understand them until they install
the updated version. So, we'll go on sending the old format to LWL
servers for a while.
"Just in case", I deleted the private items used only by the LWL
server from the SDES packet if strict is set. They're perfectly
legal but, you know....
Added unconditional padding of the whole packet to a multiple of 8
bytes in rtp_make_sdes() and rtp_make_bye(). Later on, we may want to
encrypt these packets, and it's a lot easier to pad them at generation
time when we understand the composite nature of the packets than at
encryption time, when we'd prefer to treat them as a black box.
Padding is done only for strict calls, for the same reasons given
above.
If strict is set rtp_make_sdes() now deletes the leading asterisk (if
present) from the RTCP_SDES_CNAME and RTCP_SDES_EMAIL which servers
only to inform an LWL server that the user permits exact matches only
of his E-mail address and doesn't wish to be listed in the HTML
directory. The asterisks could confuse an RTP client, so we don't
send 'em.
Modified lwld.c so it understands packets which comply with the RTP
requirement that all RTCP packets begin with an SR or RR packet. In
the future, once all the servers are running this version, we'll be
able to use the same SDES packet for the LWL server and to send to RTP
connections. I also verified that lwld.c works even if the packet it
receives contains padding. Note that only the first eligible RTCP
message in a packet is processed--If you stack multiple requests in
one packet, only the first will be processed.
Fixed a raft of byte order and bit field order independence problems
in rtpacket.c; isrtp() (this had never had the RationalWorld treatment
applied to it, since it didn't make sense to uglify it before it was
even working). I also added logic to skip a header extension, if
present. Since none of the tools I have to test with ever includes a
header extension, I can't be absolutely sure I've got this right.
Added a new isValidRTCPpacket() function to rtpacket.c, based on the
validation technique suggested in the RTP spec. This is now called
in speaker.c for two purposes. First, the protocol of a connection is
set to RTP only when a valid RTCP message is received rather than for
any control message with a version of 2. This makes it much less
likely the protocol will get set to RTP accidentally by an encrypted
VAT control message that we don't have the key to properly decode.
Second, if a DES key is supplied and we receive a message on the
control channel which passes all the tests for RTCP validity as
received, we don't decrypt it. This allows RTP programs to either
send control messages in the clear or encrypt them; both behaviours
are permitted by the RTP spec.
Fixed mike.c to encrypt RTCP BYE and VAT DONE packets when encryption
is enabled. NeVoT accepts the encrypted packets with no difficulty.
Moved the generation of VAT DONE packets from in-line code in mike.c
to a new makevatdone() function in vatpkt.c both for purity of essence
and to make it easier to move the code to Windows.
Fixed an oddity that caused VAT 4 not to recognise a DONE packet in
the form that was sent by VAT 3. I copied the VAT 3 packet, but
apparently it had garbage bits in the flags field that VAT 4 didn't
like. I zeroed the flags field and all was well.
Modified makeVATid() in vatpkt.c to take the E-mail address from the
SPEAKFREE_ID variable if no SPEAKFREE_CNAME is specified. If neither
is present, an ID is made up from the password file information as
before.
Fixed makeVATid() in vatpkt.c to delete leading asterisks on the
SPEAKFREE_CNAME and SPEAKFREE_ID E-mail addresses just like rtpacket.c
does.
Added logic in mike.c and rtpacket.c to set the marker (M) bit in the
RTP packet header for the first packet of a "talk spurt". This
conforms to the behaviour of VAT 4 in RTP mode.
Added documentation of the -rtp and -vat options to the sfmike.1
manual page.
Implemented a major revision of the "squelch" (a.k.a. VOX) code in
mike.c. While still nothing close to as nifty as Dave Hawkes' VOX
code in the Windows version, this is a great improvement over the
pathetic attempt at VOX that preceded it. This version tests the
maximum energy in a packet in the linear domain, not the logarithmic
(which, notwithstanding psychoacoustics, our users understand much
more clearly), and allows you to specify as a second comma-separated
argument to the -s option, the time in milliseconds transmission
should continue before muting transmission. In addition, the push to
talk console display now shows "Quiet:" when Talk mode is enabled and
output is squelched.
3 February 1996
Added the capability to echo VAT and RTP packets to sfecho. This
involved having echo.c monitor both control and data sockets as
sfspeaker does, and return packets received to the same port from
which they originated. The (soon to be remedied) potential ambiguity
between Speak Freely and VAT packets means uncompressed VAT packets
can be mistaken for Speak Freely sound buffers. We only consider a
packet as VAT if we've previously received a message on the control
port from this connection, and if it is in an audio format we know VAT
to use. Note that mistaking the format of a packet only affects the
log messages generated when the -v option is on; since packets are
bodily returned to the originator without examining their content, the
actual echo process does not require recognition of packet format,
Handling VAT and RTP packets without peeking inside made it impossible
to maintain the (already disabled for other good reasons) echo
server's ability to show a face file. I ripped out all the code for
that potential but ill-considered feature.
To avoid potential confusion between Speak Freely sound buffers and
VAT packets, I modified packet generation code everywhere to always
set the new fProtocol (0x40000000) bit in the compression field of
every sound buffer we send. This won't interfere with older versions
of Speak Freely, but will keep VAT compatible programs from attempting
to interpret Speak Freely packets as VAT format. (The protocol flag
turns into a VAT/RTP P value of 1, which was used by the now-obsolete
first draft of RTP. We should never see it sent by a current program.)
Once all versions of Speak Freely are sending the fProtocol bit, we'll
be able to increase our own level of discrimination between VAT and
Speak Freely packets.
Implemented another major turn of the screw to avoid spoofing by
improperly decrypted packets. RTP and VAT sound packets are now
accepted only if the session ID (conference ID for VAT, SSRC for
RTP) received in the last control message for this protocol agrees
with that contained in the sound packet. This makes it vastly less
likely we'll be fooled again by a Speak Freely sound buffer after a
protocol change or a message we can't decrypt.
To avoid incorrectly decrypted VAT and RTP packets from being
interpreted as Speak Freely sound buffers, I added a check in
speaker.c that verifies the length in the buffer.buffer_len field
against the actual length of the packet read from the socket (this
must take into account the padding to a multiple of 8 bytes which
occurs if DES, IDEA, or PGP encryption is indicated by the flags in
the header). This is a pretty good test for validity, since the odds
of 4 encrypted bytes precisely equalling the received packet length
are very slim. If a bogus packet is detected, it is ignored and the
protocol for the connection reset to PROTOCOL_UNKNOWN, which allows us
to restart protocol recognition. This, in turn, permits us to
identify unencrypted Speak Freely sound buffers which may arrive,
unless we're reset to VAT or RTP modes by the subsequent arrival of a
packet on the control port.
4 February 1996
The code which inserts a 4 random bytes before an RTCP message that's
being encrypted in sendrtpctrl() in mike.c was broken, and didn't test
whether the message was VAT (which doesn't have the random prefix) or
RTP. Fixed.
In the process of testing the above fix, I discovered that the
generation of SDES and BYE packets in rtpacket.c must actually pad
packets to an *odd* multiple of 4 bytes. Why? Because the length
of the block to be encrypted needs to be a multiple of 8 bytes, and
that includes the 4 byte random prefix. So the original packet needs
to be an odd multiple of 4.
Just a note in passing: the DES encryption used with VAT and RTP is
standard DES including the initial and final permutations which Speak
Freely dispenses with in its own modified DES. This slows down the
encryption and decryption process quite a bit (which is precisely what
it's intended to do, of course), but we have no choice since that's
what the RTP spec and VAT software require.
Padding of RTP sound packets when encrypting with DES was wrong.
Fixed.
Shuffling the pad byte to the end of the frame for LPC compressed
sound in rtpout() (rtpacket.c) wasn't quite right. Fixed. While I
was at it, I modified isrtp() to do the inverse byte shuffle rather
than call lpc_analyze() to decompress the sound. This also fixes
sfspeaker's identifying LPC compressed sound in an RTP packet as
"uncompressed".
Replaced the hokey random prefix generation for DES encrypted RTCP
packets used by sendrtpctrl() in mike.c with a proper set of random
bytes derived from the same MD5 source used for the SSRC, timestamp,
and sequence number fields.
6.0-Alpha 1 prerelease.
5 February 1996
Installed fixes for three problems reported by Jay Novello when
building on Solaris 2.4 with gcc. Two places in rtpacket.c I stored
an unsigned value > 127 into a char. Gcc natters at this, so I
changed the variable in question into an unsigned char. Let's see
what natters this sets off elsewhere (on SunOS and SGI it compiles
cleanly). Second, in soundbyte.c, the same apparent incompatibility
between stdlib.h and math.h that surfaced on SGI seems to afflict
Solaris/gcc as well. I commented out the #include of math.h and
verified that doing so didn't break anything on SunOS.
Added receive-only support for RTP PCMA (payload type 8) packets. The
A-law samples are translated into mu-law samples one for one. I
haven't been able to test this since I haven't yet found a program
which sends PCMA. There's no reason to support sending in this format,
as minimum compliance with RFC 1890 requires support of PCMU (payload
type 0), and there is no RTP channel capable of transmitting PCMA
which cannot equally well transmit PCMU. Adding PCMA inbound support
checks off another RTP payload type which we may increasingly
encounter as ISDN telephony begins to interact with the Internet.
9 February 1996
The code in speaker.c that initialises the con_session field
in the connection structure thought it was 8 bytes instead of
4. Fixed.
System V's ever-so-clever trick of blowing off pending system calls
with an EINTR status when even a timer signal occurs caused horrors in
in mike.c's sendfile() of which even Billy Boy would have been proud.
The read (Pause mode) or poll (Talk mode) of standard input to see if
we should toggle transmit can return not only when a character is
available, but also when the timer pops. Testing for -1 status
doesn't work on BSD because there you get a -1 with a WOULDBLOCK errno
when no character is available. On System V, that case returns 0
characters read and no error. So, we have to test for a return status
of -1 and errno == EINTR to decide we should retry the read. A
similar condition in the initial read to transition into Talk mode
required wrapping that read in a loop which is broken only on
non-EINTR conditions. This fixes the "jumps into Talk mode even when
I didn't press a key" and "sends a blip of sound every 7 seconds even
when I'm in Quiet" bugs.
10 February 1996
Ripped out some obsolete code in isvat.c that tried to discriminate
VAT packets from Speak Freely packets by checking the consistency of
the Speak Freely header. With the determination of the protocol based
on control channel messages and verification of the session ID in the
packet, this is no longer necessary.
Integrated some fixes to isvat.c from the Windows version which may
avoid warnings on Unix compilers pickier than those I use.
Isvat() and isrtp() used to look at information in the connection
structure when processing the packet, but no longer do. I removed the
unused connection argument, which makes the functions more portable
between the Unix and Windows versions.
12 February 1996
I decided to tackle the problems of the LPC decoder head-on. First of
all, I started with the version of LPC.C from the latest VAT source;
this version has been modified so the decoder state is kept in a
separate structure so multiple simultaneous streams don't confuse the
decoder. I further modified it to dynamically allocate the large
static and automatic arrays used in the coder and decoder; new
functions lpc_start() and lpc_end() allocate and release the work
buffer, respectively. The main rationale for this is that it's
necessary to keep these arrays out of the 64K data segment on 16 bit
Windows, and doing it here as well minimises differences in the code
and costs nothing.
To try to nail down the divide by zero and DOMAIN ERROR in sqrt()
problems, I ran various tests using standard audio test files. First
I discovered that absolute silence (rarely encountered with a real
microphone but common in edited sound files) could cause durbin() in
lpc.c to divide by zero. I added code to detect the incipient divide
by zero and return a zero gain value. This fixes the problem where
true silence was rendered as hiss. I also discovered that in certain
circumstances (probably due to roundoff of floats) the gain can go
negative by a tiny epsilon, but all it takes to make sqrt() report a
DOMAIN ERROR. I added a test for negative gain and zero the value
before the square root is taken. Both of these changes are enabled
only if SILENCEFIX is defined, which it is by default.
Given the horrors which LPC encoding results in when driven into
clipping, I added a new definition, GAIN_ADJUST, set to 0.9 by
default, which is used to scale the linearised samples before
processing. Given that many users set their mike very hot, counting
on the other coders not to mind an occasional clip, this has the
effect of reducing the gain when encoding in LPC and avoids some of
the worst clipping. Given that sound perception is logarithmic, I
don't think the difference will be very perceptible.
13 February 1996
ADPCM packets sent by sfmike in RTP protocol sounded ratty due to an
error in the calculation of RTP packet length in rtpacket.c's rtpout()
function which accidentally truncated the last two samples in the
packet. Fixed.
14 February 1996
Added an RFC 1890 string-to-key mapping for DES encryption of RTP
packets. The code was borrowed from a routine in NeVoT's netutil
directory. Both mike.c and speaker.c call the new routine in deskey.c
to generate RTP encryption keys. This new code recognises RFC 1890
encryption algorithm specifications, but only DES-CBC is accepted; any
other encryption mode exits with an error message.
To avoid protocol spoofing, I added code to reset the connection's
receive protocol to PROTOCOL_UNKNOWN when an RTP or VAT BYE/DONE
message is received and when any connection times out. If the -v
option is set, RTP and VAT bye message are now logged with a
"connection closed" message.
My code that zeroes the pad at the end of an RTP or VAT encrypted
buffer was a little too clever--it cleared the length of the pad as
well as the pad bytes! Fixed in speaker.c.
Since VAT and RTP have different conventions for converting key
strings to DES keys, I had to separate the VAT and RTP keys into
separate buffers. This causes no trouble in mike.c, but it really
bollixes up automatic protocol sensing in speaker.c. I added logic
which uses the correct key as long as the protocol is known. If the
protocol is unknown or we've received an indecipherable packet, we try
the RTP and VAT keys on alternate control channel messages until we
successfully crack a packet. Since any protocol error resets the
protocol to unknown, this should us to home in on the protocol
relatively quickly.
Added a general purpose RTCP SDES parser, parseSDES(), to rtpacket.c
and placed the definitions for the structures it uses in the new file
rtpacket.h.
If the "-v" option is specified, sfspeaker now shows the user name and
E-mail address (if available) from the identity packets received on
the control port. The user information is updated every time it
changes. The code does not currently handle packets with multiple
sources--only the first source in the packet is returned.
VAT prefers the user's long name from the password file for its
identity packets. I modified makeVATid() in vatpkt.c to behave the
same way.
I increased the packet lengths for RTP and VAT protocols to the
largest sizes within both the RTP/VAT experience base and the
the 512 byte Windows packet constraint.
Integrated a couple of byte order fixes discovered in the Windows
version into isrtp() (rtpacket.c) and isvat() (vatpkt.c).
15 February 1996
Added another little tweak to automatic protocol recognition of
encrypted control messages in speaker.c which should speed the
transition on a Speak Freely to RTP or VAT protocol change.
16 February 1996
Added code in mike.c and speaker.c and modified functions
isValidRTCPpacket(), isRTCPByepacket(), and parseSDES() in rtpacket.c
to support Speak Freely session control messages. The messages sent
and received are identical to RTP SDES packets, except the protocol is
set to 1 to indicate Speak Freely. Speak Freely never encrypts its
session control messages, so the existing check for an unencrypted
control messages takes care of this condition.
Oops--forgot to enable the periodic re-send of the SDES item if
the procotol selected is Speak Freely. Fixed.
22 February 1996
6.0-Alpha 2 prerelease.
23 February 1996
Some people ran into library incompatibilities compiling files in
libdes which aren't actually used by Speak Freely. I made a
Makefile.sf which builds only the files we need, and tweaked the
libdes/des.h file to not define crypt(), which conflicted with the
definition in unistd.h.
25 February 1996
Added logic to echo.c to recognise RTCP BYE and VAT DONE packets and
mark the connection closed without retransmitting the packet to the
other end. This fixes the problem where a user closes a connection to
the echo server, only to have it pop back open when his own BYE packet
comes back. (Yes, it seems dumb to open a connection upon receipt of
a BYE packet, but it is very easy for an encrypted RTP SDES message to
look like a VAT DONE, so we have to allow an apparent VAT DONE to open
a connection. Sigh.) Note that this will not work if the user is
sending encrypted RTP or VAT packets to the echo server. Receipt of a
BYE causes the host to go idle on the next timer tick without waiting
for the usual inactivity timeout.
Lazarus echo connections could also result if packets remained in the
retransmission queue for a given host at the time we receive a BYE
message from it. I added code in echo.c to discard any packets queued
to a host at the time it disconnects.
Modified debug output from sfecho to use a slash between the IP
address and port number, as is becoming the usual convention.
Finished "sfvod", the "voice on demand" server. Actually, this is
just a hack in Perl which monitors a port pair and, at each new
connection, forks a process which sends one or more sound files or
live audio to the connected site with sfmike. If the site disconnects
before the transmission is done, sfvod detects this and kills the
sfmike process. You can write a log in NCSA HTTPD format of all
requests processed by the server. You can run as many copies of sfvod
as you like, each monitoring a different port, to allow users to
retrieve different audio available on a host.
6.0-Alpha 3 prerelease.
26 February 1996
Once again, it's demonstrated that not even the simplest program can
esape the wiles of BSD and System V co-consipiring to pump it full of
arcana. Today's victime du jour is sfvod, which encountered the
following problems on System V. First of all, its socket recv() call
was getting nailed by System V's favourite trick, the EINTR error
return when the timer signal arrives. Further, Jay Novello reported
that on Solaris 2.4 he was getting an error return from the socket at
the end of each connection with an ECHILD status. This doesn't make
any sense according to any of the documents I have, since ECHILD isn't
a defined return status for recv(), but I put in code to ignore that
status as well as EINTR and silently retry the recv(). Next, the
timer and child process reaper signal handlers were getting clobbered
on System V because they did not re-establish the signal by
re-assigning to the %SIG variable at the end of the interrupt service
procedure. Did you know that the semantics of signal handling in Perl
depend upon whether the platform you're running is BSD or System V? I
do now.
But even that was not enough. You see, on SunOS SOCK_DGRAM is defined
as 2, while on IRIX it is 1, so the socket creation was failing since
the value of 2 I used means SOCK_STREAM on IRIX. I added an ugly hack
to the Makefile to create an ephemeral C program which is compiled and
run to insert the system's definitions of AF_INET and SOCK_DGRAM at
the head of sfvod.
27 February 1996
Speak Freely failed to sense VAT protocol when connected to a CU-SeeMe
reflector because Speak Freely required a user ID as received in a
point to point VAT connection, whereas the reflector sends IDLIST
(type 3) packets. I modified the protocol sensing logic in speaker.c
to accept IDLIST packets as indicating VAT protocol.
The CU-SeeMe reflector's periodic status packets were confusing
isvat() in vatpkt.c into returning invalid sound buffers. Fixed.
Added the ability to include a "conference ID" in VAT packets, but
since nothing seems to work if you send VAT a nonzero conference ID, I
always set it to zero at the moment.
With the advent of "voice on demand", the need to be able to transmit
pre-compressed audio has become apparent. I added a gimmick to mike.c
which, if a sound file is specified with the extension ".gsm", assumes
it to be the GSM compressed output of "toast" and transmits it in GSM
packets without any additional processing. The fact that there is no
overhead at all for these packets makes it crucial to set kOverhead
right in mike.c. It's clear I'm going to have to put in an adaptive
auto-set mode for this tweak.
28 February 1996
All the various compression and encryption modes, combined with the
wide range of machine performance encountered was beyond the ability
of the simple timing loop used when transmitting sound files. I
modified it to measure the actual time between packets, compare it to
the correct inter-packet time based on the number of samples in the
packet, and correct the wait time using an exponentially smoothed
moving average with smoothing factor of 0.9. This will, in most
cases, home in quickly on the correct delay without being upset too
much by instantaneous changes in system load.
The more accurate calculation of packet cadence times ran squarely
into an eccentricity of usleep() on BSD--if you call usleep() before
the previous setitimer has gone off, the nearer-term delay will apply.
This could lead to disaster when our own timeout went off. I modified
the private copy of usleep() in usleep.c, now renamed sf_usleep(), to
behave reasonably, including stacking and unstacking preexisting
SIGALRM handlers and interval timers. All platforms now call
sf_usleep(), eliminating the different handling of this function all
over the program.
Added a nicer status message when connected to a VAT conference that
shows who's in the conference and updates every time the members
change. I increased the size of the "user name" field (con_uname) in
the connection structure in speakfree.h to accommodate longer
conference lists and protect against lists longer than the field size
overwriting the structure.
Integrated three fixes from Eugene Crosser in mike.c and soundbyte.c
for problems experienced on Linux and with half duplex in general:
1. In mike.c line 657, if sfspeaker is not running on the local
host, soundinit() is not executed, causing soundrab to read
from unopened fd.
2. In mike.c line 1195 return from main() leaves the terminal in
noecho mode.
3. In soundbyte.c line 119 set nonblocking mode on audio is not
executed on Linux. Thus sfmike blocks in soundflush() on the
second pause/talk toggle.
6.0-Alpha 4 prerelease.
29 February 1996
When sending live audio from a Solaris system, the read() from
/dev/audio in soundgrab() (soundbyte.c) could be blown away by the
timer signal. Fixed to retry if it fails with EINTR.
Cleaned up the #ifdefs around the sound packet timing code in mike.c
to make the BSD_like and System V cases always mutually exclusive.
Sflwl could crash if "-vv" debugging was enabled and a BYE packet was
received out of the blue from host when no hosts were connected.
Fixed.
1 March 1996
When I integrated the little-endian fixes into vatpkt.c from the
Windows version, I fat-fingered two instances, using ntohs() instead
of htons(). Since these functions are, in fact, identical on every
machine I am aware of, this worked but was unclean. Scrubbed and
polished.
5 March 1996
Feature release 6.0.
10 March 1996
Revised simple (-C / 2X) compression to use the linear interpolation
rate conversion routine from "sox". It still doesn't sound great, but
it's better than it used to be.
11 March 1996
If the user combined key file encryption with one of the 8 byte frame
encryption methods (IDEA, PGP, or DES) and the original packet was not
a multiple of 8 bytes, the last frame would be incorrectly decrypted.
Speaker.c was not key-file decrypting the pad bytes at the end of the
packet as required by the subsequent decryptions. Fixed.
Integrated the NSA LPC-10 2400 baud CODEC as an option for Speak
Freely protocol. It's kept in a new lpc10 directory, and activated
with the "-lpc10" option on sfmike. Note that this CODEC is entirely
unrelated to that selected by "-lpc" and cannot be used in RTP and VAT
modes because it is not one of the forms of compression prescribed for
those protocols. Due to the extreme (better than 25 to 1) compression
of this protocol, per-packet overhead becomes a substantial part of
the bandwidth sent. I added a dirty trick called "packet stuffing"
for use with this compression mode. The no longer used 16 byte
"sendinghost" field actually carries the last 16 bytes of the packet.
Stuffed packets are re-shuffled upon receipt by speaker.c. For
compatibility, stuffing is used only with the new LPC-10 compression
mode; for the other modes the 16 byte overhead is not that significant
an overhead.
Stuffing reduces the per-packet overhead to 8 bytes, with a 78 byte
packet carrying an original payload of 1800 uncompressed samples. The
outbound data rate is, then, 346 bytes per second, or 2773 bits per
second.
22 March 1996
Sending nonencrypted packets to multiple hosts in Speak Freely
protocol on a little-endian machines failed because sendpkt() in
mike.c didn't undo the htonX() transformations of fields in the sound
buffer before sending the packet to the next destination host.
Sending nonencrypted packets to multiple hosts in Speak Freely
protocol using LPC-10 compression failed because the "packet stuffing"
done to reduce the number of bytes per packet in LPC-10 protocol was
not reversed after transmitting a packet to a given host. Fixed in
mike.c.
23 March 1996
Sending packets to multiple hosts in LPC-10 robust mode sent invalid
packets to all but the first host after the first 128 packets had
been sent. The "unstuff" code in sendpkt() in mike.c was clearing the
robust mode sequence number in the buffer.buffer_len field after
unstuffing, not before as required. Fixed.
24 March 1996
Integrated the compression type editing code from speaker.c into
echo.c so the echo server -v connection log will distinguish LPC-10
from uncompressed packets.
6.1-Alpha 1 prerelease.
28 March 1996
To avoid problems with C libraries that don't define nint(), I
incorporated the round() replacement for nint() from the CELP library
and modified all the references to nint() in the lpc10 library to use
L_nint(), which is #defined to round() in lpcdefs.h. This roundabout
redefinition allows going back to an inline implementation of nint()
if that proves important for performance reasons.
6 April 1996
In order to get rid of compiler warnings on Solaris, I added a
typedef signalFUNC to the signal function type in the #ifdef
Solaris block in speakfree.h and modified the #define signal()
for Solaris to cast its second argument to this type. In
addition, I added a definition of signalFUNCreturn which casts a
value to this type on Solaris and is void on other platforms.
This is used in usleep.c to cast the result of signal(). This
code may be applicable on other System V platforms, but I'm not
going to enable it on speculation.
All of the Speak Freely executables used argv[0] as the program
name in usage, status, and error messages. When the program was
executed with long explicit path name (as if often the case when
daemons are started at boot time), this generated a lot of clutter
in the log file. I added a prog_name() function which trims all
but the final executable name from the argv[0] string and uses that
as the program name. Sfvod.pl already contained this logic, so there
was no need to modify it.
7 April 1996
Specifying options (compression modes, for example) on sfvod to be
passed on to sfmike didn't work since they got appended to the sound
file name(s) instead of appearing before the -p specification of the
destination(s). I modified the command line parser in sfvod.pl to
distinguish sound file names from post "-" options, assemble them in
separate strings, and emit the options before the destinations on the
sfmike command line. I also added code to echo the command line when
the "-d" option is set; this makes it easier to debug what's being
passed to sfmike.
Added a new "-Wport" option to sfspeaker which causes it to do nothing
other than publish its identity on an Look Who's Listening server.
This allows sfvod servers to identify themselves without adding all
the complexity of direct communications to sfvod itself. When invoked
with "-Wport", sfspeaker does not create or bind any inbound sockets.
This allows it to coexist with other copies of sfspeaker running on
the same machine regardless of how they were invoked.
If SPEAKFREE_LWL_TELL is defined, sfvod now forks a process and
invokes sfspeaker with the -W option to announce the voice on demand
server to the LWL host.
Holy proliferating packets, Bitman! You mean it's possible for one
user to publish his identity on more than one Look Who's Listening
server? That's right, Rotten, now you can list up to five Look
Who's Listening servers on your SPEAKFREE_LWL_TELL environment
variable, separated by commas, and sfspeaker and sfecho will publish
your listing on each server you name. The limit of five is not
inherent, just intended to keep people from going off the deep end.
In addition, the SPEAKFREE_LWL_TELL hosts can be specified by IP
address as well as host name, for example (sh/ksh syntax):
SPEAKFREE_LWL_TELL="lwl.somewhere.net,12.122.85.201,lwl.elsewhere.net"
This is primarily intended to allow echo and voice on demand servers
to advertise their existence on multiple regional LWL servers, but
there's nothing to keep a user running sfspeaker from publishing on
multiple sites. Supporting this required installing the multiple site
scanning and notification code in speaker.c and echo.c, plus a small
tweak in lwl.c so that if no SPEAKFREE_LWL_ASK variable is set and
SPEAKFREE_LWL_TELL is used as the default, only the first server in
the list will be queried. (Multiple-server LWL queries have their
merits, but are better hacked in Perl than coded in C.)
8 April 1996
When I added multiple LWL publication to echo.c, I inadvertently broke
retry of failed LWL connections by echo servers. Sfspeaker gives up
on a failed LWL host immediately (to avoid bombarding former LWL
servers with packets), but echo servers are assumed to be more
responsible and since they run unattended for long periods of time,
need to be able to reconnect after an LWL server has been offline for
a while.
For the sfspeaker -d option to work with the -w (LWL only) option,
recognition of the -d option had to be moved to pass 1 option
processing in speaker.c.
Tightened up the parsing of multiple hosts on a SPEAKFREE_LWL_TELL
statement; spaces are now allowed before a host name, and a void entry
no longer fools inet_addr() into returning an IP address of 0.0.0.0.
The new code is now used by both sfspeaker and sfecho.
Added a new optional compile-time definition, AUDIO_BLOCKING, not
defined by default. If you define it, the non-Sun (i.e. Linux and
FreeBSD) code in soundbyte.c will read from the sound card with
blocking reads. This should help some drivers which don't handle
non-blocking I/O.
Memo to file: the half-duplex transition handshake between sfmike and
sfspeaker assumes sfspeaker is listening on the standard INTERNET_PORT
of 2074. If you've specified a different port with the -Pport option
on sfspeaker, a half duplex mute request from the local host will be
ignored.
6.1-Alpha 2 prerelease.
17 April 1996
Integrated a fix from Malcolm Beattie for older versions of the C
library on Linux which do not place the coprocessor into default IEEE
mode. This can result in what should be harmless floating point
underflows in lpc/lpc.c (which default IEEE handling simply rounds to
zero, as the code intends) crashing sfspeaker with a floating point
exception instead. Current libraries are supposed to set IEEE
operation by defaults and not require this fix. Since I don't have a
Linux machine to test this on, even though the fix should be harmless
on later releases, I made the fix activated only if LINUX_FPU_FIX is
defined at compile time. Mike.c and speaker.c now make a
__setfpucw(_FPU_IEEE) call at initialisation time if LINUX_FPU_FIX is
defined. I also added a comment to the Linux section of the Makefile
describing the circumstances in which the fix should be enabled.
Bradley Allen pointed out that the "#define int long" in
lpc10/lpcdefs.h could cause an error if a subsequent system include
file contained a "short int whatever;" declaration. This #define
crept in during a since-abandoned attempt to get lpc10 to work on
Windows 3.1. Since all Speak Freely for Unix platforms are 32 bit, I
just removed the #define.
Andrey A. Chernov supplied fixes for several build issues noted on
FreeBSD. The "-static" previously used on the link flags was removed
for FreeBSD 2.2. The little ephemeral program that the sfvod build
process creates in order to discover the settings of AF_INET and
SOCK_DGRAM on the current system was executed as "sfvod-t" instead of
"./sfvod-t", as required for people who, for security reasons, don't
have the current directory in their path. Finally, the "#define
const" in libdes/des.h caused lots of warning messages in FreeBSD and
keeps gcc from replacing library function calls with intrinsics. I
made the definition of const to nothing contingent on OLDCC, as is
already used for SunOS "cc" and other K&R-classic compilers.
To help diagnose oddities in translation of DES key strings into 56
bit DES keys, I added code to speaker.c to dump the computed DES keys
in hex if the -d option is set. Mike.c already did this.
18 April 1996
The -u output output from sflwl was identifying itself as the server
program, not the client. Fixed in lwl.c.
Some people have started sending huge strings to the sflwld servers,
some with embedded HTML markup. These consume lots of space in the
packets returned to requestors, and may result, for example, in not
all the echo servers being listed. I modified lwld.c to prune the
strings returned to in reply packets to a maximum of 48 characters
each, dropping HTML markup, redundant white space, and attempting when
truncation is still required, to do so at a word boundary. I also
drop non-ISO characters which may be present. This affects only
strings in reply packets--the full information sent by the user
continues to appear in the HTML active users file.
Feature release 6.1.
23 April 1996
Integrated FreeBSD and anti-zero-divide fixes for lpc/lpc.c from
Andrey A. Chernov, and also yet another byte-order fix which caused
debug traces to show incorrect packet lengths when sending sound files
on little-endian machines. I also integrated his suggestion of a
higher initial correction in the sound file timing code for FreeBSD,
since most machines which run it are slower than typical workstations.
Added the ability for Look Who's Listening servers to talk to
one another, forwarding packets they receive to as many as
LWL_MAX_SITES (defined in speakfree.h as 5) other LWL servers.
This will allow weaving the currently-isolated servers into an
interconnected web so that regardless of which server a user queries,
he can see users active on all servers which forward to one another.
Here's how it works; all modifications are to lwld.c. A new
"-f" option was added to sflwld, which accepts a comma-delimited
list of servers (and optional port numbers, preceded by a colon).
For example:
sflwld -flwl.fourmilab.ch,lwl.somewhere.edu,lwl.elsewhere.com
Any LWL packet received from a host will be forwarded to all the
hosts named in the forward list. A forwarded packet is flagged by
setting the 0x40 bit in the first byte, and contains four extra bytes
at the end which give the IP address of the originating host. Packets
forwarded from other hosts are never, themselves, forwarded: the risk
of forwarding loops is just too great and would be too difficult
to track down. Undoubtedly, a list of intercommunicating public
servers will be published so operators of a new server will know
who to forward to and how to publish the existence of their new
server. Eventually this may be automated.
In order for forwarded sites to appear on the destination host, both
the forwarding and the destination host must be running an sflwld with
the forwarding code present. No harm is done, however, by sending
forwarding messages to a pre-forwarding server--they are simply
ignored.
25 April 1996
It was possible to crash a Look Who's Listening server by sending
artfully composed bogus packets. I added an invisible Gardol shield,
in the form of an RTCP conformance test, gardol(), in lwld.c which
first makes sure any packet passes the basic RTCP validity checks of a
proper header, known payload type, and length within the packet
matching the number of bytes received (these tests are made after
forwarded packets are transformed into regular RTCP format). In
addition, the RTCP_SDES packet processor now checks for bogus packets
with no CNAME item and discards them. Finally, the code that finds
the SDES, BYE, or APP subpacket in a composite packet makes sure it
doesn't run off the end of the packet and, if no known subpacket is
found, discards the packet.
To avoid repeated "connecting forwarding socket: Connection refused"
messages when an LWL to which we're forwarding goes down, I changed
forwardLwlMessage() in lwld.c to only issue the message if the -D or
-VV options are set.
The LWL packet validation code unfortunately uncovered a failure
of the Windows version to strictly comply with the RTP spec. In
particular, the RTCP_APP packets sent to the server to request the
server message and to submit queries were not padded with zeroes to a
32 bit boundary--the packet simply terminated after the end of the
request. I'll fix this the next time I revise the Windows version,
but for compatibility with the installed base there's nothing for it
but to slightly weaken the packet consistency checking to allow this
specific case to squeak past.
28 April 1996
Andrey A. Chernov pointed out that without a #include <math.h> in
lpc10/invert.c, some compilers would incorrectly interpret the return
type of fabs(). Fixed.
29 April 1996
Plugged one more way sflwld could be tricked into aborting. If a
connection was made with a bogus protocol ID, the accept() could
fail, causing lwld.c's main loop to exit. I changed the behaviour
when the accept() fails to just ignore the error and go back to the
accept() to wait for the next connection.
2 May 1996
Integrated a fix from Brian Abernathy for an undefined gethostid() in
sfmike. Gethostid() (which is used only to build the session key) is
emulated by a call to uname() in hp_audio.c.
9 May 1996
The packet validity checking in lwld.c failed to close the accept()ed
stream socket after rejecting an invalid packet. This meant one could
crash sflwld by sending enough bogus packets to exhaust the maximum
number of open file descriptors. Fixed.
29 May 1996
Squashed a few more six-leggers that squirmed out during the first
serious test of intercontinental LWL forwarding. First of all, the
close() of the LWL socket in forwardLwlMessage() (lwld.c) was
misplaced, orphaning a file descriptor when LWL messages were
forwarded to more than one site, which eventually curtailed forwarding
when all available file descriptors were consumed. Fixed.
The time needed to connect() to a distant LWL server in
forwardLwlMessage() was long enough for System V to jab its
tried-and-true EINTR knife between our ribs. I wrapped a defensive
do {} loop around the call to silently retry it if the alarm happens
to ring while it's pending.
If -D debugging was enabled, the "received forwarded packet from"
message misleadingly displayed the IP address of the originating site
rather than the forwarding server. The message now shows the server
address, as the text strongly suggests.
24 July 1996
SunOS and Solaris (but not IRIX) systems use the same underlying
mechanism for sleep() and setitimer(). This means that a call on
sleep() has the effect of resetting the itimer to the length of the
sleep. This caused sfspeaker, when run with the -W ("LWL only")
option, to transmit its LWL message every 20 minutes rather than the
intended 10 minutes, and consequently timing out, then restarting
repeatedly. I changed the inner loop for "-W" option mode to use
pause() to wait for timer signals rather than sleep(120). This seems
to have fixed things.
To provide a little more slack in case a message to an LWL server is
lost, I increased the frequency with which LWL messages are sent in
speaker.c to one every 5 minutes. With a 15 minute timeout in sflwld,
this means three consecutive LWL notifications must fail before a site
will be timed out. Previously, failure to contact an LWL site in
speaker.c caused further transmissions to that site to be abandoned
for the duration of sfspeaker's execution. The rationale for this was
to avoid blindly bombarding down (or former) LWL sites with packets.
Unfortunately, this "one strike and you're out" policy could cause
transient failures, such as inability to connect due to network
congestion or overload on the LWL server, to shut down transmission
and cause the site to drop off the list at the server. I modified
speaker.c to only disable LWL transmissions after LWL_STRIKEOUT (5 by
default) consecutive failures to contact an LWL host; with
notification every 5 minutes, this means the host will be dropped only
if it is down for at least 25 minutes, in which case the problem is
unlikely to be transient.
27 July 1996
On systems which support POSIX threads (pthread_xxxx), sflwld can now
be built to run in multi-thread mode by compiling lwld.c with THREADS
defined. This has been tested only on Solaris 2.5 so far; you can
build a signle-thread version of sflwld as before by compiling without
THREADS defined.
Multi-thread operation not only dramatically untangles the logic of
sflwld, it eliminates the bottleneck which could cause slow response
on heavily-loaded servers, especially those which forward packets
elsewhere. Previously, all requests were processed by a single
thread, with each packet being accepted only after the previous was
completed. This meant that a query, for example, would have to wait
in the request queue until a previous SDES notification had been
forwarded to all destinations. Since forwarding is often done to
geographically remote servers, this could take a long time and have a
cascade effect when the forwarding destination servers were themselves
busy.
With THREADS defined, each request which arrives from the socket is
processed by its own thread, having no need to wait for anything
related to other requests. A critical section lock protects the
connection list from corruption due to multiple simultaneous updates,
but this lock is set only during actual updates and scans of the list
and never remains locked across a network or I/O operation which might
be time consuming. Separate processes periodically scan the
connection list to remove timed-out sites and to update the HTML list
of active sites, if configured. For each forwarding destination a
"forwarder" thread is created, which processes forwarding requests
from a queue for that specific host. If the queue exceeds
ForwarderMaxQ (currently set to 15 messages), messages to that host
are discarded until the queue falls below that level--this keeps a
non-responding forwarding destination from causing what amounts to a
memory leak in sflwld. Since each destination has its own forwarder
thread, problems in contacting one or more destinations will no longer
affect others.
Lightly-loaded servers that don't forward to remote locations will
generally work fine without THREADS defined, but if your development
environment supports POSIX threads, you'll obtain better performance
for busy servers by taking advantage of multi-thread execution.
28 July 1996
If the log information written by sflwld was redirected to a file
(for example, to make a connection log), the file was written in
block buffered mode (stdio's default handling for standard output).
This caused individual log entries not to be written as they were
created, but rather in large chunks every now and then. To allow
real-time monitoring (with tail -f, for example), I added a call to
setlinebuf(atdout) in lwld.c to guarantee that standard output is
always line buffered, even if redirected.
2 August 1996
When lwld.c was compiled for THREADS, failure to transmit a packet to
a forwarding destination in forwarder_thread() could cause the socket
file descriptor for the destination to be orphaned, leading, after
sufficiently many such reverses, to failures all over the place once
all available file handles were consumed. I changed the logic in
forwarder_thread() guarantee the socket is always closed regardless of
the outcome of the forwarding attempt.
8 August 1996
Reduced the interval of LWL retransmission for sfecho to 5 minutes
(LWL_RETRANSMIT in echo.c).
11 August 1996
Added logic to lwld.c to plug yet another way for a remote client to
consume resources within sflwld, eventually causing it to run out of
file handles and go dark to the outside world. If compiled with
THREADS, once a request was accept()ed, a socket file handle was
allocated for the use of the service_thread. If a client connected to
sflwld but never wrote anything to the socket, servicePacket() would
block indefinitely on the recv() from the socket, tying up its file
handle forever. Once enough of these zombies accumulated, accept()s
would start to fail with out of file handles. To keep this from
happening, I added logic in the main loop to make an entry in a linked
list of ballOstring packets when each thread is created, recording the
time the thread was created, its thread ID and (for debugging
purposes), the IP address of the host where the request we're
servicing originated. In normal cases, service_thread() dechains this
item and releases it before exiting with pthread_exit(). If a thread
hangs, however, timeout_thread() will, upon discovering the thread is
still waiting for input from the requesting host ServiceThreadTimeout
seconds (default 60) after the accept(), use pthread_kill() to send
SIGUSR1 to the service thread. This will be caught by killserv(),
which dechains the service thread item, closes the socket (if open),
and exits the thread. The head of the service thread list is bshead,
and the list is protected by the criticial section lock bsLock.
This fix applies only to multi-thread versions of sflwld; it's worth
noting that single-thread versions remain vulnerable to this form of
hang-up, with the even more dire consequence of just ceasing to
respond. However, given that single-thread versions have many far
more serious problems than this, which are inherent in the code, it
doesn't make sense trying to fix them at this time. If there is a
population of people who want to run heavily-loaded LWL servers and
can't get access to POSIX threads, it would make more sense to design
a new lwld.c that used fork(), or re-architect the whole mess to run
off inetd.
20 July (Moon Day) 1997
Added an experimental implementation of jitter compensation to
speaker.c. Jitter compensation is enabled with the -J option on
sfspeaker. The -J option specifies, by two comma-separated numbers,
the initial delay and length of silence which resets jitter
compensation, both in milliseconds, with 250 milliseconds the minimum
for each. If no idle time is specified, twice the jitter delay is
used; if neither delay nor idle time is given, the delay is one second
and the idle time two seconds.
For example, to accumulate samples for 3 seconds before starting to
play, and to reset the jitter timer after 4 seconds of silence, one
would specify:
sfspeaker -j3000,4000
Jitter compensation is implemented by buffering samples in memory and
only starting to play them after the jitter delay time has elapsed.
The implementation assumes the audio output device is capable of
buffering as many samples as will accumulate during the jitter
delay--if it does not do this properly, jitter compensation will be
unusable. The only alternative to requiring proper buffering in audio
output would be a multithreaded version of sfspeaker, which would make
it far less portable than assuming audio output buffering.
Implemented a rudimentary busy signal facility in speaker.c. If the
-B option is specified on the sfspeaker command line, only one
connection will be accepted at a time. If another user attempts
to connect while a connection is active, the command which follows
the -B option will be executed to notify the caller that the
sfspeaker user is occupied with another call. The command must
be a C printf() format string containing a "%s" phrase at the
point the IP address of the calling host should be inserted. If
no command is specified, the default is equivalent to specifying:
sfspeaker -b"sleep 10; sfmike %s busy.au"
The "busy.au" file is a recording of the busy signal used in North
America, with the tone repeated four times. Users should be aware
that there is no international standard for busy signals, so if you
communicate primarily with people in your area which uses a different
telephone busy signal, you might want to use a recording of that tone.
The ten second sleep is intended to increase the probability a
half-duplex user will hear the busy signal after sending the
transmission which triggers it. After a busy signal is sent to a
caller, all packets from that host are silently discarded for an
interval specified by busytimeout in the speaker.c source code, set to
60 seconds in the distribution. After that delay, additional
connection requests from the host will be processed, resulting either
in a connection or another busy signal.
It should be observed that this busy signal implementation continues
to rely upon the "community of reasonable people" model for which
Speak Freely was intended. Since a connection is closed by the remote
user "hanging up" (quitting sfmike, or closing the connection window
in the Windows version), a "denial of service attack" is possible in
which a malicious user connects to the victim and refuses to
disconnect, thereby blocking other inbound calls. If you run
sfspeaker with the -v option (as most users do), you can easily detect
this by seeing connections rejected by busy signals while a silent
connection remains active. Note that the three-minute inactivity
timeout guarantees that callers whose machines crash will not block
the receipt of other calls. If malicious refusal to disconnect
becomes a problem, a "kill file" facility may be needed. Amateur
radio has operated for the better part of a century on the assumption
some bozo will not block a QSO by sending an unmodulated
carrier--let's hope, for the moment, that Speak Freely users on the
Internet will be at least as mature and responsible.
Some implementations of make and/or shells were baffled by the
specification of the quoted release number (Relno) definition
in the Makefile. I moved this to a separate version.h file, in
which the version number must appear as the last line, quoted,
by itself. This is required so the Makefile can embed the
version in the sfvod Perl script.
21 July 1997
Swept up some lint in speaker.c.
Release 6.1c.
11 April 1998
The HTML active sites file created by makeHTML() in lwld.c displayed
the time and date of the report in UTC, but the last update time in
the local time of the site. I changed it to show all times in UTC.
12 April 1998
Completed the first cut of the new conference reflector (reflect.c)
as described in the manual page sfreflect.1.
Ported the periodic client-pull refresh (-r option) code from
reflect.c to lwld.c and added documentation to sflwld.1. I also
included the modification to etime() in lwld.c to edit the year in the
title as reflect.c now does.
Fixed some lint quibbles in lwld.c; none were serious.
Added a gimmick at the top of soundbyte.c which allows overriding the
default name for /dev/audio and specifying different audio device
files for input and output (the correct one is selected within
soundinit() depending on the iomode argument). This allows Linux
users whose drivers require opening separate /dev/audio and
/dev/audio1 devices for full-duplex to accomplish this by adding the
definitions:
-DIN_AUDIO_DEV=\"/dev/audio\" -DOUT_AUDIO_DEV=\"/dev/audio1\"
to the CCFLAGS declaration in the Makefile.
Updated dependencies in the Makefile.
14 April 1998
Cleaned up timeout and LWL update logic in reflect.c. The reflector
inherited some rather confusing timing logic from the echo server,
which needs precise timing in order to retransmit packets at the
correct time. Since the reflector immediately retransmits any
sound it receives, it doesn't need timing to any better than a second,
so I ripped out all the potentially unportable microsecond logic
and replaced it with simple calls on time() and alarm().
Okay, I finally figured out a mechanism (all right, kludge) that
permits a user to run the reflector and participate in a conference it
is mediating all on the same machine. Here are the ugly details. The
fundamental problem is that sfrelect has to bind the audio and control
ports for the conference in order to receive audio from participants
and, by doing so, blocks sfspeaker from listening to those same ports
on the machine running sfreflect. So, while a user is free to use
sfmike to transmit to the conference on the machine running sfreflect,
there's no way following the usual rules to hear the audio from the
reflector. Well, if you don't like the rules, *change them*! Enter
the "-m" (monitor) option on sfreflect. This allows you to specify a
host (and optional port number--the default is the usual Internet_Port
in the Makefile, usually 2074) to which all audio received by the
reflector is retransmitted, in addition to the conventionally
connected hosts. If you want to reflect a conference on your machine
and participate at the same time, proceed as follows:
1. Start sfspeaker as usual. We'll assume you use the
standard port of 2074.
2. Start sfreflect specifying the -mHOST option where HOST
is your machine's name. We'll assume you're using the
default port of 4074 for sfreflect.
3. Join the conference with "sfmike HOST:4074" where HOST is
as above.
Now consider what will happen. When you send to HOST:4074, sfreflect
will not echo that message back to HOST, as it is the originator
(thank goodness, since that would create an infinite audio loop!), but
will echo to the host specified by the -m option, which is the default
port on HOST, where sfspeaker will play the audio. When others send
audio, it will also be sent to the monitor host, so with this little
work-around you can reflect a conference and participate without
having two separate computers.
If a monitor site is configured, the reflector also receives control
port heartbeats from the reflector at the same time they are sent to
connected hosts.
It's ugly, but it gets you there.
15 April 1998
Well, almost there. Running the reflector and joining a conference it
is mediating on the same machine had some additional ramifications
which needed to be addressed. First of all, consider that when sfmike
is started, pointed at the reflector on the same machine, that will
cause an entry to be made in the connection table pointing to the
machine running the reflector. In the absence of a special case to
prevent it, this will cause heartbeats to be sent back to the
reflector itself (keeping it from timing out) and audio received from
sites other than the reflector to be resent to the reflector itself,
resulting in duplicate packets and stuttering audio. I added tests
in both the heartbeat and audio reflection code to skip sending a
packet when the destination host is the same as the host running the
reflector.
One additional tweak is required in the handling of a monitor host.
Since we don't want to ever locally sound originating on the local
machine (which might cause echo or feedback in the full-duplex case),
a test is needed to avoid forwarding packets originating at the same
IP address as the monitor host. Note that while most applications of
the monitor host will involve the monitor host being identical to that
running the reflector, this test is correct in the general case. If
the reflector is running on a "headless" server with no audio hardware
and sending monitor packets to a different workstation, we still don't
want to reflect packets originating at that workstation back to
itself.
16 April 1998
Added a test for localhost (127.0.0.1) as an alias for the actual IP
address of the machine running the reflector in each of the three
places we test to avoid forwarding a packet to ourselves. I hope I've
gotten the byte-order independence right on this test, but all the
machines I've tested it on are big-endian.
19 April 1998
The HTML status documents created by sflwld and sfreflect were
vulnerable to unquoted HTML control sequences embedded in text
supplied by users. While some users took advantage of this to
include HTML links, others supplied incorrect HTML which caused some
or all of the balance of the file to be discarded by the browser.
I added an outHTML() function in the new file html.c which quotes all
HTML sensitive characters as they are transcribed.
23 July 1998
The lpcdecomp() function in speaker.c was using ntohl()
instead of ntohs() to extract the uncompressed length from
the first two bytes of buffer_val. This may be the source
of the reports of "deafening static" by Linux users.
The gsmdecomp() function in speaker.c was missing the required
ntohs() when extracting the uncompressed length. This seems
to have done no harm since the length was immediately fixed by
the sanity check which follows. I added the call to avoid the
need to be saved by the sanity check. I also extended the
sanity check to first try a byte swap before forcing the field
to the full packet length. This should make speaker.c accept
either big- or little-endian values in this field.
To ease the transition from prior releases with the byte
order bug in GSM packets, I added a variant of the "-t"
option in mike.c, "-tc", which causes the GSM length field
to be sent correctly, in network byte order. This option
is meaningful only on little-endian machine (since on
big-endian machines, host and network byte order are
identical). Specifying the -tc option allows a little-endian
Unix host to communicate with a Windows machine or big-endian
Unix machine running a release prior to 6.1e. In addition,
if BYTE_SWAP_DEBUG is defined, a -td option is available which
unconditionally swaps the bytes in the GSM length field. This
was included solely to permit testing the compatibility code
in speaker.c from sfmike running on a big-endian machine.
Added the following message when speaker.c fails to open
audio output in the hope of reducing the puzzlement of
those plagued with a half-duplex /dev/audio driver:
opening audio output device: No such device or address
A common cause of this error is a sound board or
driver which cannot run in full duplex mode (some
boards which are physically capable of full duplex
have drivers which cannot run them in this mode).
Try uncommenting the line:
DUPLEX = -DHALF_DUPLEX
in the Makefile, then "make clean", then "make".
This will operate your board in half-duplex mode
and avoid the conflict which probably caused the
error opening audio output.
17 September 1998
Removed an extra argument to a fprintf in debug code in
speaker.c which was spotted by the SGI C 7.2.1 compiler.
Release 6.1e.
2 March 1999
The two tests for robust mode packet replication in mike.c
used lpc10comp function as the conditional for the test instead
of the lpc10compress flag. This didn't cause any problem
since the function name was always equivalent to TRUE and
"robust" never gets set unless the correct flag, lpc10compress,
is set. This error was nailed by the SGI IRIX 6.5 C compiler,
and is now fixed to use lpc10compress.
Added Blowfish as an encryption option in sfmike.c and sfspeaker.c,
with both programs using the "-bf" option to specify the key. The
Blowfish library is built in a new blowfish subdirectory. Blowfish is
operated in 128 bit mode, with the actual key generated from the
user-supplied key with the MD5 algorithm. Since the "-b" option
was previously used by sfspeaker to specify an arbitrary busy
signal command, I added a note to the sfspeaker manual page
observing that in the unlikely event the first character of the
busy signal command should be "f", one can simply quote the command
(if not already quoted) and precede it with a space, which the shell
will ignore.
I made a slight modification to the Blowfish library to automatically
set the BF_PTR optimisation flag in blowfish/bf_locl.h if "sparc"
or "mips" is defined at compile time. This avoids having to set
these flags via CFLAGS. This is only a speed optimisation; the
code will work correctly with this variable mis-set. The code
recommends defining BF_PTR2 for Intel machines prior to the
Pentium Pro, again purely as a speed optimisation. I did not
attempt to do this, since I know of no preprocessor symbol valid
on all x86 compilers which allows detecting such processors
unambiguously. Further, I made no attempt to use any of the
assembly language inner loops provided with the code. Since
Blowfish encryption and decryption is so fast (once the key has
been generated, which only happens once per execution of sfmike
and sfspeaker) compared to GSM, LPC, or LPC-10 compression,
even without perfect optimisation settings Blowfish will account
for a very small fraction of the CPU time per packet.
3 March 1999
Added documentation for Blowfish encryption to the sfmike.1 and
sfspeaker.1 manual pages and cleaned up some awkward phraseology which
had accreted over the years.
Sfvod, which works perfectly fine on Perl 4.036, failed on Perl 5.004
in a bizarre manner which took the better part of a day to track down.
The problem ended up being a stone bug in Perl 5.004: if a signal
was processed while blocked in recv() waiting for a packet to arrive,
when the next packet was received, recv() would return the null string
for the sender's address, even through the data for the packet was
properly stored into the string argument. I happened to notice that
the UDP example program in "Programming Perl, 2nd ed." did not block
on recv() but instead called select()--it had to, since it was waiting
on multiple clients. Okay, I thought, let's use a totally unnecessary
select() (since sfvod listens only to one socket) and see if that
works around the bug. Damned if it didn't, and the modified code
works on both Perl 4 and 5. I thought about using the timeout feature
in select() to replace the existing alarm() mechanism (it would be
safer, as &tick() would always be called in a known environment), but
the Perl manual warns that you can't be sure select() will return
a valid time left value on all platforms, which could potentially
cause the timeout to be disabled due to inter-packet arrival times
less than the tick interval.
4 March 1999
I added a "text chat" feature to mike.c and speaker.c to allow people
to send text messages while they're trying to establish a reliable
audio link (or for any other reason). When you're running in push
to talk mode in sfmike, pressing the period (.) key now displays a
"Chat:" prompt, pausing audio transmission if it was in progress.
The user can then enter a line of text in regular input mode, and
when Return is pressed, the text is sent to all destinations on
the control port as an RTCP APP message with type "SFtc". Upon
receiving such a message, sfspeaker prints its content on standard
output, prefixed with the best available information about the sender,
in decreasing order of preference: user name, E-mail address, host
name, and IP address.
Previously, speaker.c didn't bother to decode the identity information
in RTCP SDES packets unless the option to show connections was set.
Since this information may be needed to identify senders of text
chat packets, I modified it to always decode SDES packets. The
overhead is negligible.
The loop-back mode in speaker.c contained obsolete logic to compute
packet length which resulted in its sending extra bytes at the end
of the packet returned to the sender. This ran afoul of the packet
length sanity check in the recipient's sfspeaker, causing the packet
to be discarded. Fixed.
For some screwball reason I can't make head or tails of, if you quit
sfmike while in talk mode on Silicon Graphics IRIX 6.5, not only
does Speak Freely exit but the Winterm you're running it under
also quits, closing the window where you're running sfmike. This
does not happen on Solaris, nor does it happen if you run sfmike
under the SGI debugger. I've tried all the obvious things, including
completely simulating transition back to pause mode and waiting
10 seconds before exiting, but at the moment the exit() is executed,
bye-bye Winterm. Precisely the same thing happens if you run sfmike
under xterm, or under csh or sh instead of ksh. However, if you run
sfmike with the "-a" option (always transmit), and kill it with
Control C in mid-transmission, everything shuts down just fine.
Beats me. Well, after another hour of flailing around, I discovered
that moving the fcntl(fileno(stdin), F_SETFL, 0) which sets stdin
back into blocking I/O mode after the call to switch back to
cooked mode rather than before fixes the disappearing shell window
problem. Sigh. If you need to revisit this, look at function
exiting() in mike.c.
Updated sfmike.1 and sfspeaker.1 manual pages, and revised the
introductions to each to be more generic in terminology across
various Unix platforms.
5 March 1999
Fixed a typo (actually, a blind-copy-o) in speaker.c's how-to-call
text; in sfspeaker, the -BF option decrypts, not encrypts. (Spotted
by RZG).
Release 6.1f.
5 April 1999
Fixed a harmless extra argument on the SHOW_SOCKET fprintf debug
code in echo.c.
Implemented fixes to lpc/lpc.c forwarded by Enzo Michelangeli.
These should eliminate distortion primarily due to overflows in
computing parameters. LPC still doesn't sound great, but it
shouldn't break up so badly due to clipping. These fixes
interoperate with no problems with pre-fix LPC CODECs so there's
no problem earlier versions.
6 April 1999
The current version and release date is defined in version.h, which
was included in speakfree.h to make it available to each main program.
This created a Makefile dependency of speakfree.h on version.h, which
created the curious situation that if you updated version.h and did
not modify speakfree.h, every program which included speakfree.h would
be rebuilt on every make. I modified each program which actually
needs the version (echo.c, lwl.c, lwld.c, mike.c, reflect.c, and
speaker.c) to explicitly include version.h, removed the include of it
from speakfree.h, and updated the dependencies in the Makefile to
reflect these changes.
Release 6.1g.
2 May 1999
Text chat messages sent to a reflector operated by sfreflect caused it
to crash attempting to interpret the RTCP APP message as an SDES.
Added code to reflect.c to detect text chat packets received on the
control port, reformat them to embed the sender's identity in the text
area (since otherwise they'll contain only the identity of the
reflector), and retransmit them to the control port of all connected
hosts (and the monitoring host, if any).
Added code to soundbyte.c, conditional on LINUX_DSP_SMALL_BUFFER,
which attempts to limit the input sound buffer size to 2048 bytes.
I have not personally tested this code and LINUX_DSP_SMALL_BUFFER
is not defined by default.
Release 6.1h.
17 May 1999
Redesignated as Release 7.0 to synchronise with Windows release.
Other than the version change, there are no changes in this release.
Release 7.0.
25 August 1999
Added a -w option to mike.c which dumps raw audio input to a
binary file. This is intended to facilitate debugging of audio
input hardware which requires special settings to produce input
in the 8000 sample per second 8 bit mu-law encoding expected by
sfmike.
30 August 1999
Integrated code from Jean-Marc Orliaguet to support Linux (and
other platform) audio hardware which doesn't support 8 bit
mu-law audio. Defining LINEAR_NEEDED includes code which translates
on the fly between 16 bit PCM and mu-law. As I have no audio hardware
which requires this, this code has not been tested other than to
verify that it compiles correctly when enabled.
Integrated code from Jean-Marc Orliaguet to add a new "-e" option
to sfspeaker. When a new connection is opened, the argument to
the "-e" option is executed as a command, with the character sequence
"%s" replaced by the hostname of the connecting hosts. One might,
for example, answer calls automatically with:
sfspeaker -e"killall sfmike >&! /dev/null; sfmike %s"
31 August 1999
The half-duplex muting code which coordinates handing the
audio device back and forth between sfmike and sfspeaker was
unnecessarily looking up the local host's name and IP
address, which could fail under certain bizarre circumstances.
I modified it to use the standard local loopback address of
127.0.0.1 which, in the interest of paranoia, I supplied
definitions for in mike.c and speaker.c in case some
screwball system doesn't define it in <netinet/in.h> as it's
supposed to.
Turned off code in mike.c introduced in release 6.1e to transition
from the incorrect GSM byte order sent by little-endian platforms
prior to that release. To send the correct byte order, you needed
to use the -TC option on sfmike. Now that almost everybody is
running versions which understand the corrected byte order, this
has been made the default. If you absolutely have to transmit to
a Unix user running an older version on a little-endian platform,
you can specify "-TD" to force the old, incorrect, byte order.
Release 7.0b.
1 September 1999
Added a test in mike.c for failure of gethostname(). If a system is
sufficiently misconfigured that it can't obtain its own host name,
we just call it "localhost" rather than in all likelihood crashing
due to an uninitialised value for the host name.
Removed obsolete "OLD2X" compression code in mike.c and speaker.c.
It's not like we were going to re-enable "mumble mode" compression
some day.
Removed conditional code in mike.c based on definition of
TINY_PACKETS. This definition has been required for years, and
the code which predated it was obsolete and confusing in some
places.
The new files common.c and common.h, added by Jean-Marc Orliaguet
to support the "-e" option in sfspeaker (execute command on
connection) contained ANSI C function declaration syntax. I
downgraded this to K&R to maintain the tradition that Speak
Freely can be built even on ancient versions of SunOS which
don't come with an ANSI compiler. I added a #include of common.h
to speakfree.h, which allowed dispensing with the explicit
(and potentially dangerous, as pointer and integers need not
have the same length) casts in speaker.c. The code which expanded
the reply command did not check for failure to allocate the expanded
command and didn't release the dynamically allocated command buffer,
creating a memory leak on each connection. Fixed.
Changed des/ and idea/ from object files explicitly linked into
sfmike and sfspeaker to libraries like the other crypto packages
(libdes/ and blowfish/).
Added the ability to build no-crypto versions of sfspeaker and sfmike
(the only components of Speak Freely for Unix which include encryption
code). If "NOCRYPTO" is defined at compile time, speakfree.h will not
define the symbol "CRYPTO" on which all encryption code in mike.c and
speaker.c is now conditional. At link time, the various encryption
libraries will not be pulled in since no references to them appear
in the main programs. On non-crypto builds the how-to-call
instructions (-u option) on sfmike and sfspeaker identify themselves
as non-crypto versions and provide the URL from which full crypto
source code can be obtained. In addition, if the non-crypto version
of sfspeaker receives encrypted audio, it emits a warning (once per
connection) which explains why it is unable to decode the audio and
again directs the user to the URL for a full crypto edition.
The rationale for the non-crypto version is precisely the same as
motivated the creation of the non-crypto Windows edition; it permits
the creation of ready-to-run binaries for widely used platforms such
as Linux and FreeBSD which can be freely distributed without concern
for export controls and other regulations on encryption technology.
Once a user installs such an edition and gets it to work transmitting
in the clear (which one should do in any case before experimenting
with encryption), they can then download a version with encryption
and replace the binary they initially received.
Note that non-crypto builds apply only to *binary* distributions
of Speak Freely. Any source distribution includes all of the
encryption modules and must be treated as cryptographic software.
Integrated fixes from Walter Haidinger (walter.haidinger@gmx.at)
to provide fine-grained control over the size and number of buffers
used by the Linux OSS audio input driver. If LINUX_DSP_SMALL_BUFFER
is defined, you may now also specify:
FRAGMENT_BUFSIZE=32
FRAGMENT_BUFPOWER=8
which set the size of individual audio input "fragments" to
(2 ^ FRAGMENT_BUFPOWER) and the number of fragments in the
overall buffer FRAGMENT_BUFSIZE. Mr. Haidinger reports that the
values given above result in about one second of audio delay with
no lost audio on his configuration. Note that these settings have
no effect whatsoever unless LINUX_DSP_SMALL_BUFFER is also
defined. See the Makefile Linux configuration section for
additional details, and the README.Linux_OSS_bufsize document for
an in depth explanation.
Integrated code from Walter Haidinger to add an "install" target
to the Makefile. I set the default installation target directory
tree to /usr/local. Binaries and manual pages are installed under
root:root with permissions of 755 and 644 respectively. Note that
you may have to edit the path for the INSTALL program at the
top of the Makefile.
Changed the default path to Perl in the Makefile to /usr/bin/perl.
This seems more common these days that the prior setting of
/usr/local/bin/perl.
Removed some OBSOLETE-flagged code from vatpkt.c.
Removed some OLDWAY-flagged code from rtpacket.c handling LPC
compressed RTP messages.
Release 7.0c.
13 September 1999
Fixed a typo in a debug message related to busy signal generation
in speaker.c.
Completed the first cut of sflaunch (launch.c), which opens the
audio device in O_RDWR mode and then executes sfmike and sfspeaker
in two child processes, passing the audio I/O and control file
descriptors to them with the -y# option. This allows working around
audio device drivers which don't allow two separate programs to
open the audio device simultaneously, even if one opens read-only
and the other write-only. (Which remains, in my opinion, a
stone bug. Why should audio input and output have anything to
do with one another, necessarily, and why must both be owned
by the same program?) Anyway, sflaunch should allow those with
such drivers to run Speak Freely.
14 September 1999
Removed a redundant definition of BUFL in soundbyte.c. It is
defined in speakfree.h, which soundbyte.c includes.
Removed the confusing SGI audio driver from the end of soundbyte.c
and placed it in its own file, audio_sgi.c. Renamed the former
hp_audio.c to audio_hp.c. The intent is that all future drivers
for non-device-file audio will be named audio_something.c. Now
each driver only contains one set of the audio interface functions.
Several Speak Freely source files used the <ctype.h> functions
such as isspace(), tolower(), but there was no include of <ctype.h>
in speakfree.h. Fixed. (This didn't cause a problem on any known
platform, but it generates lint natters.)
In half duplex mode, mike.c did not call soundflush() on the first
transition between Pause and Talk mode. On some platforms,
particularly Solaris (which has a large input buffer), this
could cause in a long transmission of sound received before
the user made the switch to talk mode. Fixed.
Release 7.0d.
15 September 1999
Added g711.o to the list of object files required to build sflaunch
when -DNEEDED_LINEAR is defined. (Fix supplied by Jean-Marc
Orliaguet.)
18 September 1999
Fixed a couple of typos and troff formatting uglies in the manual
page sflaunch.1.
Made Linux the default settings in the Makefile.
The "closing audio device" debug message at the end of launch.c
appeared even if the -d option was not specified. Fixed; I didn't
notice this until testing on Linux since the message is only
compiled in when AUDIO_DEVICE_FILE is defined, and I'd been
testing on SGI, which does not define this flag.
Release 7.1.